//
//  NSObject+JSON.m
//  mmbang
//
//  Created by 杨世昌 on 14/12/9.
//  Copyright (c) 2014年 iyaya. All rights reserved.
//

#import "NSObject+JSON.h"
#import <objc/runtime.h>
#import "NSData+String.h"

@implementation NSObject (JSON)


/**
 *  json string to dict
 *
 *  @param jsonString json
 *
 *  @return dict
 */
+ (NSDictionary *)jsonStringToDict:(NSString *)jsonString
{
    NSError *error = nil;
    NSDictionary *jsonDict = nil;
    @try {
         jsonDict = [NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]
                                                                 options:kNilOptions
                                                                   error:&error];
    } @catch (NSException *exception) {
        NSLog(@"===== json convert exception :%@",exception);
    } @finally {
        
    }
    
    
    if (error) {
        NSLog(@"error = %@",error);
    }
    
    return jsonDict;
}

/**
 *  object to json data
 *
 *  @return to json data
 */
-(NSData *)toJsonData
{
    NSData *jsonData = nil;
    
    NSError *error = nil;
    
    jsonData = [NSJSONSerialization dataWithJSONObject:self options:0 error:&error];
    
    if (error) {
        jsonData = nil;
    }
    
    return jsonData;
}

/**
 *  convert json to json string
 *
 *  @return jsonString
 */
-(NSString *)toJsonString
{
    NSData *jsonData = [self toJsonData];
    if (jsonData) {
        return [jsonData toString];
    }else{
        return nil;
    }
}

/**
 *  convert model to dict
 *
 *  @return dict
 */
-(NSDictionary *)toDict
{
    NSMutableDictionary *dict;
    
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    
    unsigned int outCount, i;
    
    objc_property_t *properties = class_copyPropertyList([self class], &outCount);
    
    for (i = 0; i < outCount; i++){
        
        objc_property_t property = properties[i];
        
        NSString *key = [NSString stringWithFormat:@"%s",property_getName(property)];
        
        id value = [self valueForKey:key];
        
        if (value) {
            dict[key]= value;
        }
    }
    
    free (properties);
    
#pragma clang diagnostic pop
    
    return dict;
}






#pragma mark - dictionary from attributes

- (NSDictionary *)dictionaryDescriptionForClassType:(Class)classType  {
    NSMutableDictionary * result = [NSMutableDictionary dictionaryWithCapacity:0];
    
    Class superClass  = class_getSuperclass(classType);
    
    if(superClass != nil && ![superClass isEqual:[NSObject class]])
    {
        [result addEntriesFromDictionary:[self dictionaryDescriptionForClassType:superClass]];
    }
    
    unsigned int		  property_count;
    objc_property_t * property_list = class_copyPropertyList(classType, &property_count);
    
    for (int i = property_count - 1; i >= 0; --i) {
        objc_property_t property = property_list[i];
        
        const char * property_name = property_getName(property);
        NSString * propertyName = [NSString stringWithCString:property_name encoding:NSASCIIStringEncoding];
        
        if (propertyName) {
            id value = [self valueForKey:propertyName];
            if (value) {
                if ([value isKindOfClass:[NSArray class]]) {
                    NSMutableArray *myMembers = [NSMutableArray array];
                    
                    for (id valueMember in value) {
                        NSDictionary *populatedMember = [valueMember dictionaryFromAttributes];
                        [myMembers addObject:populatedMember];
                    }
                    
                    value = myMembers;
                    [result setObject:value forKey:propertyName];
                    
//                } else if([value isKindOfClass:[BaseModel class]]){
//                    value = [value dictionaryFromAttributes];
//                    [result setObject:value forKey:propertyName];
                } else {
                    [result setObject:value forKey:propertyName];
                }
            }
        }
    }
    free(property_list);
    
    return result;
    
}

- (NSDictionary *)dictionaryFromAttributes
{
    return [self dictionaryDescriptionForClassType:[self class]];
}


#pragma mark - auto description

- (NSString *) autoDescriptionForClassType:(Class)classType
{
    
    NSMutableString * result        = [NSMutableString string];
    
    Class superClass                = class_getSuperclass(classType);
    
    if (superClass != nil && ![superClass isEqual:[NSObject class]])
    {
        [result appendString:[self autoDescriptionForClassType:superClass]];
    }
    
    unsigned int		  property_count;
    
    objc_property_t * property_list = class_copyPropertyList(classType, &property_count);
    
    for (int i = property_count - 1; i >= 0; --i)
    {
        objc_property_t property        = property_list[i];
        
        const char * property_name      = property_getName(property);
        NSString * propertyName         = [NSString stringWithCString:property_name encoding:NSASCIIStringEncoding];
        
        if (propertyName) {
            id value  = [self valueForKey:propertyName];
            // format of result items: p1 = v1; p2 = v2; ...
            [result appendFormat:@"%@ = %@; ", propertyName, value];
        }
    }
    
    free(property_list);
    
    return result;
}

/**
 *  auto description
 *
 *  @return object description
 */
- (NSString *) autoDescription
{
    return [NSString stringWithFormat:@"[%@ {%@}]", NSStringFromClass([self class]), [self autoDescriptionForClassType:[self class]]];
}

@end
